package net.jcip.examples.chapter8;

import java.util.concurrent.*;
/**
 * 在上述代码中，可能会导致线程饥饿死锁的原因如下：
 *
 * 单线程 ExecutorService：代码中使用了 Executors.newSingleThreadExecutor() 创建了一个单线程的 ExecutorService (exec)。这意味着所有提交给这个 ExecutorService 的任务都将在同一个线程中顺序执行。
 *
 * 任务间的依赖关系：RenderPageTask 类中的 call() 方法提交了两个任务 header 和 footer，它们分别加载 header.html 和 footer.html 文件。这两个任务被提交后，RenderPageTask 中的主任务继续执行 renderBody() 方法渲染页面的主体内容。
 *
 * 依赖的 Future 获取：在 RenderPageTask 的 call() 方法中，当执行到 return header.get() + page + footer.get(); 这一行时，主任务试图获取 header 和 footer 任务的结果。这里的 get() 方法是阻塞的，即主任务会等待 header 和 footer 任务执行完成并返回结果。
 *
 * 死锁可能性：由于 exec 是单线程的 ExecutorService，而 header.get() 和 footer.get() 方法会阻塞主任务的执行，如果 header 任务中也依赖于 footer 任务的结果（或反之），就会出现死锁。具体来说：
 *
 * RenderPageTask 等待 header 和 footer 任务的结果。
 * header 和 footer 任务被提交到了同一个单线程的 ExecutorService 中，它们必须在同一个线程中执行。
 * 如果 header 任务依赖于 footer 任务的结果，而 footer 任务又依赖于 header 任务的结果，就形成了相互等待对方完成的死锁情况。
 * 解决方案：要避免这种线程饥饿死锁的情况，可以考虑以下几种方式：
 *
 * 使用多线程 ExecutorService，例如 Executors.newCachedThreadPool()，以便任务可以并发执行。
 * 在提交任务时，避免任务之间形成循环依赖或者互相等待的情况。
 * 尽量减少在 get() 方法上的阻塞调用，或者使用 CompletionService 等方式处理任务结果，避免主任务在等待过程中阻塞整个线程。
 * 总结来说，线程饥饿死锁的根本原因在于任务之间的相互依赖以及单线程 ExecutorService 导致的串行执行。避免这种情况的关键是合理安排任务的提交和结果获取顺序，确保不会在任务间形成循环依赖或者互相等待的情况。
 */
public class ThreadDeadlock {
    ExecutorService exec = Executors.newSingleThreadExecutor();

    public class LoadFileTask implements Callable<String> {
        private final String fileName;

        public LoadFileTask(String fileName) {
            this.fileName = fileName;
        }

        public String call() throws Exception {
            // Here's where we would actually read the file
            return "";
        }
    }

    public class RenderPageTask implements Callable<String> {
        public String call() throws Exception {
            Future<String> header, footer;
            header = exec.submit(new LoadFileTask("header.html"));
            footer = exec.submit(new LoadFileTask("footer.html"));
            String page = renderBody();
            // Will deadlock -- task waiting for result of subtask
            return header.get() + page + footer.get();
        }

        private String renderBody() {
            // Here's where we would actually render the page
            return "";
        }
    }
}
